package auth

import (
	"fmt"
	"goProject/db"
	"goProject/table"
	"strings"
	"sync"
	"time"

	"github.com/casbin/casbin/v2/model"

	"gitee.com/ruige_fun/util/rlog"
	"github.com/kataras/iris/v12"
	"github.com/kataras/iris/v12/context"

	"github.com/casbin/casbin/v2"
	gormAdapter "github.com/casbin/gorm-adapter/v3"
)

//CASBIN内容   角色ID   请求路径   请求方法

const casbinConf = `
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)
`

// RegisterRouter 注册路由，顺便往 table.MenuItemURL 里丢，方便普通用户CASBIN鉴权。
// menuItemID 所属的页面ID，详见 table.MenuItem 的ID。为0时，不进行路径注册。
// auth.RegisterRouter(1, app, "GET", "/profile", profile)
func RegisterRouter(menuItemID uint, app iris.Party, method string, path string, handlers context.Handler) {
	if app == nil {
		return
	}
	method = strings.ToUpper(method)
	switch method {
	case "GET":
		app.Get(path, handlers)
	case "POST":
		app.Post(path, handlers)
	case "PUT":
		app.Put(path, handlers)
	case "DELETE":
		app.Delete(path, handlers)
	default:
		rlog.Error("iris注册请求失败：", method, path)
		return
	}
	if menuItemID <= 0 {
		return
	}
	db.MySQL.Create(&table.MenuItemURL{
		Path:       fmt.Sprint(app.GetRelPath(), path),
		Method:     method,
		MenuItemID: menuItemID,
	})
}

var CASBIN *casbin.Enforcer

func init() {
	a, err := gormAdapter.NewAdapterByDB(db.MySQL)
	if err != nil {
		rlog.Error("CASBIN 请求鉴权初始化失败：", err)
	}
	fromString, err := model.NewModelFromString(casbinConf)
	if err != nil {
		rlog.Error("CASBIN 请求鉴权初始化失败：", err)
	}
	CASBIN, err = casbin.NewEnforcer(fromString, a)
	if err != nil {
		rlog.Error("CASBIN 请求鉴权初始化失败：", err)
	}
	err = CASBIN.LoadPolicy()
	if err != nil {
		rlog.Error("CASBIN 请求鉴权初始化失败：", err)
	}
}

var lAutoAddPolicy = sync.Mutex{}

// AutoAddPolicy 自动读取数据的请求链接，生成CASBIN鉴权。
func AutoAddPolicy() {
	now := time.Now()
	lAutoAddPolicy.Lock()
	defer lAutoAddPolicy.Unlock()
	CASBIN.ClearPolicy()    //清理所有的规则，然后重新建立规则
	_ = CASBIN.SavePolicy() //保存到数据库

	var allRole []table.Role //记录普通角色列表
	db.MySQL.Where("`id` > ?", 2).Find(&allRole)

	var count = 0
	for _, d := range allRole {
		var allMenuItem []table.RoleMenuItem //记录当前普通角色，拥有的所有菜单项（页面）权限
		db.MySQL.Where("`role_id` = ?", d.ID).Find(&allMenuItem)
		for _, item := range allMenuItem {
			var allPath []table.MenuItemURL //记录当前普通角色，当前菜单项（页面）下路的所有请求信息
			db.MySQL.Where("`menu_item_id` = ?", item.MenuItemID).Find(&allPath)
			for _, req := range allPath {
				_, _ = CASBIN.AddPolicy(fmt.Sprint(d.ID), req.Path, req.Method)
				count++
			}
		}
	}
	rlog.Success("CASBIN 请求鉴权，重新建立权限表完成，累计", count, "项，耗时", time.Since(now))
}
